unit DUnitX.RttiUtils;
interface
uses Rtti, SBD.Generics, SYsutils;

type

TAttributes = class
  public
    class function Get<T: TCustomAttribute>( Subject: TRttiObject): ISEnumerable<T>;
    class function GetFirst<T: TCustomAttribute>( Subject: TRttiObject; out Attri: T): boolean;
    class function Has<T: TCustomAttribute>( Subject: TRttiObject): boolean;
  end;

{$REGION 'Internal only'}
type
TAttributesEnumerable<T: TCustomAttribute> = class ( TSEnumerable<T>)
  private
    FSubject: TRttiObject;
  protected
    function GetEnumerator: ISEnumerator<T>;         override;
  public
    constructor Create( Subject: TRttiObject);
  end;

type
TAttributesCursor<T: TCustomAttribute> = class( TSEnumerator<T>)
  private
    FAll: TArray<TCustomAttribute>;
    FIdx: integer;
  protected
    function MoveNext: boolean;                        override;
    function GetCurrent: T;                            override;
  public
    constructor Create( Enumerable1: TSEnumerable<T>);  override;
  end;
{$ENDREGION}



implementation





class function TAttributes.Get<T>( Subject: TRttiObject): ISEnumerable<T>;
begin
result := TAttributesEnumerable<T>.Create( Subject)
end;

class function TAttributes.GetFirst<T>( Subject: TRttiObject; out Attri: T): boolean;
var
  Run: T;
begin
Attri := Default( T);
for Run in Get<T>( Subject) do
  begin
  Attri := Run;
  break
  end;
result := assigned( Attri)
end;


class function TAttributes.Has<T>( Subject: TRttiObject): boolean;
var
  Dummy: T;
begin
result := TAttributes.GetFirst<T>( Subject, Dummy)
end;

constructor TAttributesEnumerable<T>.Create( Subject: TRttiObject);
begin
FSubject := Subject
end;



function TAttributesEnumerable<T>.GetEnumerator: ISEnumerator<T>;
begin
result := TAttributesCursor<T>.Create( self);
end;

constructor TAttributesCursor<T>.Create( Enumerable1: TSEnumerable<T>);
begin
inherited Create( Enumerable1);
FAll := (Enumerable1 as TAttributesEnumerable<T>).FSubject.GetAttributes;
FIdx := -1
end;

function TAttributesCursor<T>.GetCurrent: T;
begin
result := T( FAll[ FIdx])
end;

function TAttributesCursor<T>.MoveNext: boolean;
begin
while FIdx < Length( FAll) do
  begin
  Inc( FIdx);
  if (FIdx < Length( FAll)) and FAll[ FIdx].InheritsFrom( T) then break
  end;
result := FIdx < Length( FAll)
end;



end.
